%%
%% Main share process for the receiver and sender. Here mainly sort the nodes by the CPU Percent,
%% and delegate to the "share_ordered" function.
%% 
%% Parameters:
%% 	GossipReceive: Gossip information for the receive side
%%  GossipSend: Gossip information for the sender side
%%
%% Parameter formats: {{ID, TakenCPU, TakenMEM, PLAN}, {CPU, MEM}}
%% PLAN = [{CID, CPU, MEM}]
%%
share(GossipReceive, GossipSend)->
	{GossipDataReceive, {CPUR, _MEMR}} = GossipReceive,
	{GossipDataSend, {CPUS, _MEMS}} = GossipSend,
	{_IDR, TCPUR, _TMEMR, _PLANR} = GossipDataReceive,
	{_IDS, TCPUS, _TMEMS, _PLANS} = GossipDataSend,
	if
		TCPUR/CPUR >= TCPUS/CPUS ->
			share_ordered(GossipReceive, GossipSend);
		true ->
			{B, A} = share_ordered(GossipSend, GossipReceive),
			{A, B}
	end.

%%
%% Actual share process for the two nodes. Split the configuration plan, prioritily share by common parts.
%% 
%% Parameters:
%% 	GossipL: Gossip information for the node that has larger pressure
%%  GossipS: Gossip information for the node that has smaller pressure
%%
%% Parameter formats: {{ID, TakenCPU, TakenMEM, PLAN}, {CPU, MEM}}
%% PLAN = [{CID, CPU, MEM}]
%%
share_ordered(GossipL, GossipS)->
	{GossipDataL, {CPUL, _MEML}} = GossipL,
	{GossipDataS, {CPUS, MEMS}} = GossipS,
	{IDL, TCPUL, _TMEML, PLANL} = GossipDataL,
	{IDS, TCPUS, TMEMS, PLANS} = GossipDataS,
	DeltaCPU = (TCPUL * CPUS - TCPUS * CPUL) div (CPUL + CPUS),
	if
		DeltaCPU >0 ->
			{{PLANLC, PLANLD}, {PLANSC, PLANSD}} = split(PLANL, PLANS),
			if
				length(PLANLC) > 0 ->
					PLANLCNew = sort_unit_mem(PLANLC, -1),
					{PLANLCNewShared, PLANSCShared, DeltaCPUNew} = share_common(PLANLCNew, PLANSC, DeltaCPU),
					if
						DeltaCPUNew == 0 ->
							calc_plan(IDL, lists:append(PLANLCNewShared, PLANLD), IDS, lists:append(PLANSCShared, PLANSD));
						true ->
							share_ordered_next(PLANLCNewShared, PLANLD, PLANSCShared, PLANSD, DeltaCPUNew, MEMS-TMEMS, IDL, IDS)
					end;
				true ->
					share_ordered_next(PLANLC, PLANLD, PLANSC, PLANSD, DeltaCPU, MEMS-TMEMS, IDL, IDS)
			end;
		true ->
			{GossipDataL, GossipDataS}
	end.

%%
%% Actual share process for the two nodes (continue).If share of common parts not enough or not applicable,
%% then share by adjusting the different parts.
%% 
%% Parameters:
%% 	PLANLC: Common configuration plan parts for the node Large
%%  PLANLD: Different parts for the node Large
%%  PLANSC: Common parts for the node Small
%%  PLANSD: Different parts for the node Small
%%  DeltaCPU: CPU to be shifted (after the previous shift action)
%%  MAXMEM: Max MEM can be consumed by this shift action
%%  IDL: ID of the node Large
%%  IDS: ID of the node Small
%%
%% Parameter formats: PLAN = [{CID, CPU, MEM}]
%%
share_ordered_next(PLANLC, PLANLD, PLANSC, PLANSD, DeltaCPU, MAXMEM, IDL, IDS) ->
	if
		length(PLANLD) >0 ->
			PLANLDNew = sort_unit_mem(PLANLD, 1),
			{PLANLDNewShared, PLANSDShared, _DeltaCPUNew} = share_different(PLANLDNew, PLANSD, DeltaCPU, MAXMEM),
			calc_plan(IDL, lists:append(PLANLC, PLANLDNewShared), IDS, lists:append(PLANSC, PLANSDShared));
		true ->
			calc_plan(IDL, lists:append(PLANLC, PLANLD), IDS, lists:append(PLANSC, PLANSD))
	end.

%%
%% Calculate the return format when the detail plan is ready.
%% 
%% Parameters:
%%  IDL: ID of the node Large
%%  PLANL: Configuration plan for node Large
%%  IDS: ID of the node Small
%%  PLANS: Configuration plan for node Small
%%  
%%  Parameter formats: PLAN = [{CID, CPU, MEM}]
%%
calc_plan(IDL, PLANL, IDS, PLANS)->
	{calc_plan(IDL, PLANL), calc_plan(IDS, PLANS)}.

%%
%% Calculate the return format when the detail plan is ready (for one node).
%% 
%% Parameters:
%%  IDL: ID of the node
%%  PLANL: Configuration plan for the node
%%  
%%  Parameter formats: PLAN = [{CID, CPU, MEM}]
%%
calc_plan(IDL, PLANL)->
	CPUList = [CPU || {_CID, CPU, _MEM} <- PLANL],
	MEMList = [MEM || {_CID, _CPU, MEM} <- PLANL],
	TakenCPU = lists:sum(CPUList),
	TakenMEM = lists:sum(MEMList),
	{IDL, TakenCPU, TakenMEM, PLANL}.